<!-- author: xuett -->
<!-- date: 2024-07-12 09:49:22 -->
<!-- description: 缩放框 -->
<template>
  <div
    class="scale-box"
    :style="{ left: scaleInfo.left + 'px', top: scaleInfo.top + 'px', width: scaleInfo.width + 'px', height: scaleInfo.height + 'px' }"
    @mousedown="mousedown($event)"
  >
    <div
      :class="['scale-btn', `scale-btn-${direction}`]"
      v-for="direction in btnList"
      :key="direction"
      @mousedown.stop="scaleMousedown($event, direction)"
    ></div>
  </div>
</template>

<script setup>
const $props = defineProps({
  containerInfo: {
    type: Object,
    defasult: () => {}
  }
});
const $emit = defineEmits(["asyncChartInfo"]);

const btnList = ["lt", "tm", "tr", "rm", "rb", "bm", "bl", "lm"];

//鼠标信息
const mouseInfo = {
  onMove: false,
  x: 0,
  y: 0,
  offsetX: 0, //鼠标距离选中模型左边界的距离
  offsetY: 0 //鼠标距离选中模型上边界的距离
};

const scaleInfo = reactive({
  left: 0,
  top: 0,
  width: 0,
  height: 0,
  onScale: false,
  direction: "" //缩放方向
});

// 同步缩放信息到选中组件
const asyncScaleInfo = (activeChart, event = null) => {
  // 将选中组件尺寸同步到缩放框
  const { left, top, width, height } = activeChart;
  scaleInfo.left = left;
  scaleInfo.top = top;
  scaleInfo.width = width;
  scaleInfo.height = height;
  if (event) {
    mousedown(event);
  }
};

// 鼠标按下事件
const mousedown = (event) => {
  event.preventDefault();
  mouseInfo.onMove = true;
  mouseInfo.offsetX = event.clientX - scaleInfo.left;
  mouseInfo.offsetY = event.clientY - scaleInfo.top;
};

//缩放按钮按下事件
const scaleMousedown = (event, direction) => {
  event.preventDefault();
  scaleInfo.onScale = true;
  mouseInfo.x = event.clientX;
  mouseInfo.y = event.clientY;
  scaleInfo.direction = direction;
};

//鼠标松开事件
const mouseup = () => {
  mouseInfo.onMove = false;
  if (scaleInfo.onScale) {
    scaleInfo.onScale = false;
    $emit("asyncChartInfo", scaleInfo);
  }
};

//判断事件类型
const handleEventType = (event) => {
  if (mouseInfo.onMove) {
    handleDrag(event); //拖拽事件
  } else if (scaleInfo.onScale) {
    handleScale(event); //缩放事件
  }
};

//drag事件结束
const handleDrag = (event) => {
  let left = event.clientX - mouseInfo.offsetX;
  let top = event.clientY - mouseInfo.offsetY;
  // 边界判断
  if (handleBoundary(left, top, scaleInfo.width, scaleInfo.height)) {
    mouseInfo.onMove = false;
    return;
  }
  scaleInfo.left = left;
  scaleInfo.top = top;
  //同步位置到选中组件
  $emit("asyncChartInfo", scaleInfo);
};

//缩放按钮移动事件
const handleScale = (event) => {
  let left = event.clientX - mouseInfo.x; //鼠标移动了的距离
  let top = event.clientY - mouseInfo.y;
  let cLeft = scaleInfo.left,
    cTop = scaleInfo.top,
    cWidth = scaleInfo.width,
    cHeight = scaleInfo.height; //组件的位置、宽高

  //计算八个位置的缩放，从左上角开始顺时针
  switch (scaleInfo.direction) {
    case "lt":
      cLeft += left;
      cTop += top;
      cWidth -= left;
      cHeight -= top;
      break;
    case "tm":
      cTop += top;
      cHeight -= top;
      break;
    case "tr":
      cTop += top;
      cWidth += left;
      cHeight -= top;
      break;
    case "rm":
      cWidth += left;
      break;
    case "rb":
      cWidth += left;
      cHeight += top;
      break;
    case "bm":
      cHeight += top;
      break;
    case "bl":
      cLeft += left;
      cWidth -= left;
      cHeight += top;
      break;
    case "lm":
      cLeft += left;
      cWidth -= left;
      break;
  }
  //边界判断
  if (handleBoundary(cLeft, cTop, cWidth, cHeight)) {
    scaleInfo.onScale = false;
    $emit("asyncChartInfo", scaleInfo);
    return;
  }
  mouseInfo.x = event.clientX;
  mouseInfo.y = event.clientY;
  //更新缩放框信息
  scaleInfo.left = cLeft;
  scaleInfo.top = cTop;
  scaleInfo.width = cWidth;
  scaleInfo.height = cHeight;
};

//边界判断
const handleBoundary = (left, top, width, height) => {
  let errorFlag = false;
  // 边界判断
  if (left < 0 || top < 0) {
    errorFlag = true;
  } else if (left + width > $props.containerInfo.domWidth) {
    errorFlag = true;
  } else if (top + height > $props.containerInfo.domHeight) {
    errorFlag = true;
  }
  return errorFlag;
};

defineExpose({ asyncScaleInfo, handleEventType, mouseup });
</script>

<style scoped lang="scss">
.scale-box {
  border: 1px solid #409eff;
  position: absolute;
  left: 500px;
  top: 200px;
  cursor: move;
  // z-index: 1;
  .scale-btn {
    width: 10px;
    height: 10px;
    border: 2px solid #409eff;
    background-color: #fff;
    position: absolute;
  }
  .scale-btn-lt {
    left: -5px;
    top: -5px;
    cursor: nw-resize;
  }
  .scale-btn-tm {
    left: calc(50% - 5px);
    top: -5px;
    cursor: n-resize;
  }
  .scale-btn-tr {
    right: -5px;
    top: -5px;
    cursor: ne-resize;
  }
  .scale-btn-rm {
    right: -5px;
    top: calc(50% - 5px);
    cursor: e-resize;
  }
  .scale-btn-rb {
    right: -5px;
    bottom: -5px;
    cursor: se-resize;
  }
  .scale-btn-bm {
    bottom: -5px;
    left: calc(50% - 5px);
    cursor: s-resize;
  }
  .scale-btn-bl {
    bottom: -5px;
    left: -5px;
    cursor: sw-resize;
  }
  .scale-btn-lm {
    left: -5px;
    top: calc(50% - 5px);
    cursor: w-resize;
  }
}
</style>
